package com.yudao.demo;

import org.apache.poi.xwpf.usermodel.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.List;
import java.util.Map;

/**
 * Word文档模板工具类
 * 用于将Map数据填充到docx模板文件中
 */
public class WordTemplateUtil {
    // 占位符前缀和后缀常量
    private static final String PLACEHOLDER_PREFIX = "${";
    private static final String PLACEHOLDER_SUFFIX = "}";

    /**
     * 填充Word模板
     * 
     * @param templatePath 模板文件路径
     * @param outputPath 输出文件路径
     * @param dataMap 要填充的数据Map
     * @return 是否填充成功
     */
    public static boolean fillTemplate(String templatePath, String outputPath, Map<String, String> dataMap) {
        // 检查必要参数
        if (isInvalidParams(templatePath, outputPath, dataMap)) {
            return false;
        }
        
        // 检查模板文件是否存在
        File templateFile = new File(templatePath);
        if (!templateFile.exists() || !templateFile.isFile()) {
            logError("模板文件不存在或不是有效文件: " + templatePath);
            return false;
        }
        
        // 创建输出目录（如果不存在）
        if (!createOutputDirectory(outputPath)) {
            return false;
        }
        
        // 使用try-with-resources自动管理资源
        try (FileInputStream fis = new FileInputStream(templateFile);
             XWPFDocument document = new XWPFDocument(fis);
             FileOutputStream fos = new FileOutputStream(outputPath)) {
            
            // 处理文档内容
            processParagraphs(document, dataMap);
            processTables(document, dataMap);
            
            // 保存修改后的文档
            document.write(fos);
            fos.flush();
            System.out.println("文档填充完成，已保存至: " + outputPath);
            return true;
            
        } catch (Exception e) {
            logError("填充Word模板时发生错误: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 检查参数是否有效
     */
    private static boolean isInvalidParams(String templatePath, String outputPath, Map<String, String> dataMap) {
        if (templatePath == null || templatePath.isEmpty() || 
            outputPath == null || outputPath.isEmpty() || 
            dataMap == null) {
            logError("参数错误: 模板路径、输出路径或数据映射为空");
            return true;
        }
        return false;
    }
    
    /**
     * 创建输出目录
     */
    private static boolean createOutputDirectory(String outputPath) {
        File outputFile = new File(outputPath);
        File outputDir = outputFile.getParentFile();
        
        if (outputDir != null && !outputDir.exists()) {
            if (!outputDir.mkdirs()) {
                logError("无法创建输出目录: " + outputDir.getAbsolutePath());
                return false;
            }
        }
        return true;
    }
    
    /**
     * 记录错误信息
     */
    private static void logError(String message) {
        System.err.println(message);
    }
    
    /**
     * 处理文档中的所有段落
     */
    private static void processParagraphs(XWPFDocument document, Map<String, String> dataMap) {
        if (document == null || dataMap == null) {
            return; // 避免空指针异常
        }
        
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        if (paragraphs == null || paragraphs.isEmpty()) {
            return;
        }
        
        for (XWPFParagraph paragraph : paragraphs) {
            if (paragraph == null) continue;
            
            try {
                String text = paragraph.getText();
                if (text != null && containsPlaceholder(text, dataMap)) {
                    replaceInParagraph(paragraph, dataMap);
                }
            } catch (Exception e) {
                logError("处理段落时发生错误: " + e.getMessage());
                // 继续处理下一个段落
            }
        }
    }
    
    /**
     * 检查文本是否包含需要替换的占位符
     */
    private static boolean containsPlaceholder(String text, Map<String, String> dataMap) {
        for (String key : dataMap.keySet()) {
            if (key != null && text.contains(createPlaceholder(key))) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 创建完整的占位符字符串
     */
    private static String createPlaceholder(String key) {
        return PLACEHOLDER_PREFIX + key + PLACEHOLDER_SUFFIX;
    }
    
    /**
     * 处理文档中的所有表格
     */
    private static void processTables(XWPFDocument document, Map<String, String> dataMap) {
        if (document == null || dataMap == null) {
            return; // 避免空指针异常
        }
        
        List<XWPFTable> tables = document.getTables();
        if (tables == null || tables.isEmpty()) {
            return;
        }
        
        for (XWPFTable table : tables) {
            if (table == null) continue;
            
            List<XWPFTableRow> rows = table.getRows();
            if (rows == null || rows.isEmpty()) continue;
            
            for (XWPFTableRow row : rows) {
                if (row == null) continue;
                
                List<XWPFTableCell> cells = row.getTableCells();
                if (cells == null || cells.isEmpty()) continue;
                
                for (XWPFTableCell cell : cells) {
                    if (cell == null) continue;
                    
                    processCellParagraphs(cell, dataMap);
                }
            }
        }
    }
    
    /**
     * 处理表格单元格中的段落
     */
    private static void processCellParagraphs(XWPFTableCell cell, Map<String, String> dataMap) {
        List<XWPFParagraph> paragraphs = cell.getParagraphs();
        if (paragraphs == null || paragraphs.isEmpty()) return;
        
        for (XWPFParagraph paragraph : paragraphs) {
            if (paragraph == null) continue;
            
            try {
                String text = paragraph.getText();
                if (text != null && containsPlaceholder(text, dataMap)) {
                    replaceInParagraph(paragraph, dataMap);
                }
            } catch (Exception e) {
                logError("处理单元格段落时发生错误: " + e.getMessage());
                // 继续处理下一个段落
            }
        }
    }
    
    /**
     * 在段落中替换占位符
     * 保持原有格式（斜体、粗体、字体颜色等）
     */
    private static void replaceInParagraph(XWPFParagraph paragraph, Map<String, String> dataMap) {
        if (paragraph == null || dataMap == null) {
            return;
        }
        
        List<XWPFRun> runs = paragraph.getRuns();
        if (runs == null || runs.isEmpty()) {
            return;
        }
        
        String paragraphText = paragraph.getText();
        if (paragraphText == null) {
            return;
        }
        
        // 检查段落是否需要处理
        if (!containsPlaceholder(paragraphText, dataMap)) {
            return;
        }
        
        // 用于跟踪是否进行了替换
        boolean hasReplacements = false;
        
        // 处理单独运行元素中包含的完整占位符
        hasReplacements = processIndividualRuns(runs, dataMap);
        
        // 如果没有在单个运行元素中找到完整占位符，则处理占位符被拆分的情况
        if (!hasReplacements) {
            processSplitPlaceholders(paragraph, runs, paragraphText, dataMap);
        }
    }
    
    /**
     * 处理单独运行元素中的占位符
     */
    private static boolean processIndividualRuns(List<XWPFRun> runs, Map<String, String> dataMap) {
        boolean hasReplacements = false;
        
        for (XWPFRun run : runs) {
            if (run == null) continue;
            
            String text = run.getText(0);
            if (text == null) continue;
            
            String modifiedText = text;
            boolean runModified = false;
            
            for (Map.Entry<String, String> entry : dataMap.entrySet()) {
                if (entry.getKey() == null) continue;
                
                String placeholder = createPlaceholder(entry.getKey());
                if (modifiedText.contains(placeholder)) {
                    String replacement = entry.getValue() != null ? entry.getValue() : "";
                    modifiedText = modifiedText.replace(placeholder, replacement);
                    runModified = true;
                    hasReplacements = true;
                }
            }
            
            if (runModified) {
                try {
                    run.setText(modifiedText, 0);
                } catch (Exception e) {
                    // 忽略单个运行元素的错误
                }
            }
        }
        
        return hasReplacements;
    }
    
    /**
     * 处理占位符被拆分到多个运行元素的情况
     */
    private static void processSplitPlaceholders(XWPFParagraph paragraph, List<XWPFRun> runs, 
                                               String paragraphText, Map<String, String> dataMap) {
        // 保存第一个运行元素的样式，用于保持格式
        XWPFRun firstRun = runs.get(0);
        
        // 应用所有数据映射的替换
        String newParagraphText = paragraphText;
        boolean hasReplacements = false;
        
        for (Map.Entry<String, String> entry : dataMap.entrySet()) {
            if (entry.getKey() == null) continue;
            
            String placeholder = createPlaceholder(entry.getKey());
            String replacement = entry.getValue() != null ? entry.getValue() : "";
            
            if (newParagraphText.contains(placeholder)) {
                newParagraphText = newParagraphText.replace(placeholder, replacement);
                hasReplacements = true;
            }
        }
        
        // 如果有替换发生，重新构建段落
        if (hasReplacements && firstRun != null) {
            try {
                // 保存第一个运行元素的样式信息
                StyleInfo styleInfo = extractStyleInfo(firstRun);
                
                // 清除所有运行元素的内容
                clearRunsContent(runs);
                
                // 在第一个运行元素中设置替换后的文本
                firstRun.setText(newParagraphText, 0);
                
                // 恢复原始样式
                applyStyleInfo(firstRun, styleInfo);
            } catch (Exception e) {
                // 忽略重建段落的错误
            }
        }
    }
    
    /**
     * 提取运行元素的样式信息
     */
    private static StyleInfo extractStyleInfo(XWPFRun run) {
        StyleInfo styleInfo = new StyleInfo();
        try {
            styleInfo.isBold = run.isBold();
            styleInfo.isItalic = run.isItalic();
            styleInfo.underline = run.getUnderline();
            styleInfo.fontFamily = run.getFontFamily();
            styleInfo.fontSize = run.getFontSize();
            styleInfo.color = run.getColor();
            styleInfo.isStrike = run.isStrike();
        } catch (Exception e) {
            // 忽略获取样式信息的错误，使用默认值
        }
        return styleInfo;
    }
    
    /**
     * 清除所有运行元素的内容
     */
    private static void clearRunsContent(List<XWPFRun> runs) {
        for (XWPFRun run : runs) {
            if (run != null) {
                run.setText("", 0);
            }
        }
    }
    
    /**
     * 应用样式信息到运行元素
     */
    private static void applyStyleInfo(XWPFRun run, StyleInfo styleInfo) {
        try {
            applyOriginalStyles(run, styleInfo.isBold, styleInfo.isItalic, styleInfo.underline, 
                               styleInfo.fontFamily, styleInfo.fontSize, styleInfo.color, styleInfo.isStrike);
        } catch (Exception e) {
            // 忽略应用样式的错误
        }
    }
    
    /**
     * 样式信息类，用于存储和传递文本样式属性
     */
    private static class StyleInfo {
        boolean isBold = false;
        boolean isItalic = false;
        UnderlinePatterns underline = UnderlinePatterns.NONE;
        String fontFamily = null;
        int fontSize = -1;
        String color = null;
        boolean isStrike = false;
    }
    
    /**
     * 应用原始运行元素的样式到新的运行元素
     */
    private static void applyOriginalStyles(XWPFRun run, boolean isBold, boolean isItalic, 
                                          UnderlinePatterns underline, String fontFamily, 
                                          int fontSize, String color, boolean isStrike) {
        if (run == null) {
            return; // 避免空指针异常
        }
        
        // 应用字体设置
        if (fontFamily != null) {
            safeApply(() -> run.setFontFamily(fontFamily));
        }
        
        if (fontSize != -1) {
            safeApply(() -> run.setFontSize(fontSize));
        }
        
        // 应用样式设置
        safeApply(() -> run.setBold(isBold));
        safeApply(() -> run.setItalic(isItalic));
        safeApply(() -> run.setUnderline(underline));
        safeApply(() -> run.setStrike(isStrike));
        
        // 应用颜色设置
        if (color != null) {
            safeApply(() -> run.setColor(color));
        }
    }
    
    /**
     * 安全应用样式设置，忽略异常
     */
    private static void safeApply(Runnable action) {
        try {
            action.run();
        } catch (Exception e) {
            // 忽略单个属性应用错误
        }
    }
    
    /**
     * 简单的格式保留方法，确保替换文本时保留原始格式
     */
    private static void preserveFormatting(XWPFRun sourceRun, XWPFRun targetRun) {
        if (sourceRun == null || targetRun == null) {
            return;
        }
        
        try {
            // 复制字体设置
            String fontFamily = sourceRun.getFontFamily();
            if (fontFamily != null) {
                safeApply(() -> targetRun.setFontFamily(fontFamily));
            }
            
            int fontSize = sourceRun.getFontSize();
            if (fontSize != -1) {
                safeApply(() -> targetRun.setFontSize(fontSize));
            }
            
            // 复制样式设置
            safeApply(() -> targetRun.setBold(sourceRun.isBold()));
            safeApply(() -> targetRun.setItalic(sourceRun.isItalic()));
            safeApply(() -> targetRun.setUnderline(sourceRun.getUnderline()));
            safeApply(() -> targetRun.setStrike(sourceRun.isStrike()));
            
            // 复制颜色
            String color = sourceRun.getColor();
            if (color != null) {
                safeApply(() -> targetRun.setColor(color));
            }
        } catch (Exception e) {
            logError("复制格式时发生错误: " + e.getMessage());
        }
    }
}